{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#优化岭回归参数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当你使用岭回归模型进行建模时，需要考虑`Ridge`的`alpha`参数。\n",
    "\n",
    "例如，用OLS（普通最小二乘法）做回归也许可以显示两个变量之间的某些关系；但是，当`alpha`参数正则化之后，那些关系就会消失。做决策时，这些关系是否需要考虑就显得很重要了。\n",
    "\n",
    "<!-- TEASER_END -->"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##Getting ready"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这是我们第一个进行模型参数优化的主题，通常用交叉检验（cross validation）完成。在后面的主题中，还会有更简便的方式实现这些，但是这里我们一步一步来实现岭回归的优化。\n",
    "\n",
    "在scikit-learn里面，岭回归的$\\Gamma$参数就是`RidgeRegression`的`alpha`参数；因此，问题就是最优的`alpha`参数是什么。首先我们建立回归数据集："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from sklearn.datasets import make_regression\n",
    "reg_data, reg_target = make_regression(n_samples=100, n_features=2, effective_rank=1, noise=10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##How to do it..."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在`linear_models`模块中，有一个对象叫`RidgeCV`，表示**岭回归交叉检验（ridge cross-validation）**。这个交叉检验类似于**留一交叉验证法（leave-one-out cross-validation，LOOCV）**。这种方法是指训练数据时留一个样本，测试的时候用这个未被训练过的样本："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "RidgeCV(alphas=array([ 0.1,  0.2,  0.3,  0.4]), cv=None, fit_intercept=True,\n",
       "    gcv_mode=None, normalize=False, scoring=None, store_cv_values=False)"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "from sklearn.linear_model import RidgeCV\n",
    "rcv = RidgeCV(alphas=np.array([.1, .2, .3, .4]))\n",
    "rcv.fit(reg_data, reg_target)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "拟合模型之后，`alpha`参数就是最优参数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.10000000000000001"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rcv.alpha_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里，`0.1`是最优参数，我们还想看到`0.1`附近更精确的值："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "RidgeCV(alphas=array([ 0.08,  0.09,  0.1 ,  0.11,  0.12]), cv=None,\n",
       "    fit_intercept=True, gcv_mode=None, normalize=False, scoring=None,\n",
       "    store_cv_values=False)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rcv = RidgeCV(alphas=np.array([.08, .09, .1, .11, .12]))\n",
    "rcv.fit(reg_data, reg_target)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.080000000000000002"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rcv.alpha_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以按照这个思路一直优化下去，这里只做演示，后面还是介绍更好的方法。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##How it works..."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上面的演示很直接，但是我们介绍一下为什么这么做，以及哪个值才是最优的。在交叉检验的每一步里，模型的拟合效果都是用测试样本的误差表示。默认情况使用平方误差。更多细节见`There's more...`一节。\n",
    "\n",
    "我们可以让`RidgeCV`储存交叉检验的数据，这样就可以可视化整个过程："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "RidgeCV(alphas=array([ 0.0001 ,  0.00112,  0.00214,  0.00316,  0.00417,  0.00519,\n",
       "        0.00621,  0.00723,  0.00825,  0.00927,  0.01028,  0.0113 ,\n",
       "        0.01232,  0.01334,  0.01436,  0.01538,  0.01639,  0.01741,\n",
       "        0.01843,  0.01945,  0.02047,  0.02149,  0.0225 ,  0.02352,\n",
       "        0.02454,  0.02556...4185,\n",
       "        0.04287,  0.04389,  0.04491,  0.04593,  0.04694,  0.04796,\n",
       "        0.04898,  0.05   ]),\n",
       "    cv=None, fit_intercept=True, gcv_mode=None, normalize=False,\n",
       "    scoring=None, store_cv_values=True)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "alphas_to_test = np.linspace(0.0001, 0.05)\n",
    "rcv3 = RidgeCV(alphas=alphas_to_test, store_cv_values=True)\n",
    "rcv3.fit(reg_data, reg_target)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你会看到，我们测试了0.0001到0.05区间中的50个点。由于我们把`store_cv_values`设置成`true`，我们可以看到每一个值对应的拟合效果："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(100, 50)"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rcv3.cv_values_.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "通过100个样本的回归数据集，我们获得了50个不同的`alpha`值。我们可以看到50个误差值，最小的均值误差对应最优的`alpha`值："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.014357142857142857"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "smallest_idx = rcv3.cv_values_.mean(axis=0).argmin()\n",
    "alphas_to_test[smallest_idx]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "此时问题转化成了“RidgeCV认可我们的选择吗？”可以再用下面的命令获取`alpha`值："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.014357142857142857"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rcv3.alpha_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "通过可视化图形可以更直观的显示出来。我们画出50个测试`alpha`值的图："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\no1i6dCkA77//PmeffTZ169alXr16nH322bz33nu0atWKyZMn079/f95//31233133nzzTWbOnEm7\ndu1o06YNb731Fl988QVmVuz5C1qyZAkjR47kkksuoW/fvtxzzz3Mnj27XNc6b15owfncc+qgLulB\niU+kCEcccQQzZ84scludAi0+atSowbZt24Adzx52bHN3zIxf/OIXzJ49m5YtW3LHHXdw1113AXDp\npZcye/ZsZs+ezeLFi/njH/+Iuxd7/oJGjhxJz549AWjUqBEfffQRe+65505f58cfQ7du8PDD0Lnz\nTh8ukpSU+ESK0LlzZ7Zs2cKwYcN2rJs3bx5ffvllscccf/zxjB8/nh9++IHvv/+e8ePHc/zxx7Ny\n5Up23XVXevbsyU033cSsWbPo0qULY8eOZc2aMNrfunXrdqqqcuvWrfz85z8HYNOmTdSrV4/jjjtu\np65x2TI46aTwXO/cc3fqUJGkpmmJRIrx0ksv0a9fPwYNGsSuu+7KQQcdxAMPPPCTatD8923atOG3\nv/0tRx99NAB9+vThyCOP5PXXX+fmm29ml112oVatWjz66KM0b96cu+++m5NPPpm8vDxq1arFI488\nwt57713s+Qvq06cPL7/8Ml9++SVmRseOHRk7diznnHNOma7t66/h17+GG2+E3/2uPHdHJHmpO4NI\nAXl5eeyS4j22162DTp3g/PPhjjvijkZk56g7g0gCrV+/nho1avCXv/wl7lAqzYYN0LVreK53++1x\nRyMSD5X4RAh97erXrw/Ali1bqF27dswRJd6mTSHhHX44PPIIlNBwVaTaSkSJT4lP0t6WLVvYdddd\ngdBQpG7dujFHlHhbt4aZFvbcU+NvSnJT4hOpoG3btlGrVi0AvvvuO3bfffeYI0q8rVtDq80aNWDM\nGKipJm2SxPSMT6QC8ltTAnzzzTcpm/TOOy+U8J57TklPBNSdQdKUu1OjRg0AVqxYUa7O39Vdbm5o\nuekeSnop+NhSpFyU+CTtuPuOLgtLly5lv/32izmixMtPetu3w9ixSnoiBSnxSdrJb7yyZMkSDjzw\nwJijSbzcXLjwwlDN+eKLSnoihSnxSVpp0qQJW7ZsYc6cOTRr1izucBIuNxcuugh++EETyYoUR4lP\n0kbLli1ZsWIFH374IUceeWTc4SRcbi707Anff6+kJ1ISJT5JC5mZmcyfP58333yTDh06xB1Owm3e\n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\n+EREJK38P3zaaajIO8KTAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7c129e8>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt\n",
    "f, ax = plt.subplots(figsize=(7, 5))\n",
    "ax.set_title(r\"Various values of $\\alpha$\")\n",
    "\n",
    "xy = (alphas_to_test[smallest_idx], rcv3.cv_values_.mean(axis=0)[smallest_idx])\n",
    "xytext = (xy[0] + .01, xy[1] + .1)\n",
    "\n",
    "ax.annotate(r'Chosen $\\alpha$', xy=xy, xytext=xytext,\n",
    "            arrowprops=dict(facecolor='black', shrink=0, width=0)\n",
    "            )\n",
    "ax.plot(alphas_to_test, rcv3.cv_values_.mean(axis=0));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##There's more..."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果我们想用其他误差自定义评分函数，也是可以实现的。前面我们介绍过MAD误差，我们可以用它来评分。首先我们需要定义损失函数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def MAD(target, prediction):\n",
    "    absolute_deviation = np.abs(target - prediction)\n",
    "    return absolute_deviation.mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "定义损失函数之后，我们用`sklearn`量度中的`make_scorer`函数来处理。这样做可以标准化自定义的函数，让scikit-learn对象可以使用它。另外，由于这是一个损失函数不是一个评分函数，是越低越好，所以要用`sklearn`来把最小化问题转化成最大化问题："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.050000000000000003"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import sklearn\n",
    "MAD = sklearn.metrics.make_scorer(MAD, greater_is_better=False)\n",
    "rcv4 = RidgeCV(alphas=alphas_to_test, store_cv_values=True, scoring=MAD)\n",
    "rcv4.fit(reg_data, reg_target)\n",
    "smallest_idx = rcv4.cv_values_.mean(axis=0).argmin()\n",
    "alphas_to_test[smallest_idx]"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
